package com.yike.user.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.yike.common.constant.CommonConstant;
import com.yike.common.enums.MachineCodeEnum;
import com.yike.common.exception.BusinessException;
import com.yike.common.redis.RedisUtil;
import com.yike.common.tool.*;
import com.yike.common.vo.LoginUserInfoVo;
import com.yike.common.vo.ShopVo;
import com.yike.user.convert.ShopConvert;
import com.yike.user.convert.UserConvert;
import com.yike.user.entity.*;
import com.yike.user.mapper.UserAuthorizeMapper;
import com.yike.user.mapper.UserFileMapper;
import com.yike.user.mapper.UserMapper;
import com.yike.user.mapper.UserSettingMapper;
import com.yike.user.param.*;
import com.yike.user.service.MachineService;
import com.yike.user.service.ShopService;
import com.yike.user.service.UserDetailService;
import com.yike.user.service.UserService;
import com.yike.common.base.BaseServiceImpl;
import com.yike.common.pagination.Paging;
import com.yike.common.pagination.PageInfo;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yike.user.utils.ZtskUtil;
import com.yike.user.vo.UserFileVo;
import com.yike.user.vo.UserSettingVo;
import com.yike.user.vo.UserVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.transaction.annotation.Transactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 用户表 服务实现类
 *
 * @author yike
 * @since 2024-07-17
 */
@Slf4j
@Service
public class UserServiceImpl extends BaseServiceImpl<UserMapper, User> implements UserService {

    @Value("${user.password-error-num}")
    Integer PASSWORD_ERROR_NUM;

    @Resource
    private UserMapper userMapper;

    @Autowired
    UserDetailService userDetailService;

    @Autowired
    ShopService shopService;

    @Autowired
    private CommonUtil commonUtil;

    @Autowired
    RedisUtil redisUtil;

    @Autowired
    private MachineService machineService;

    @Autowired
    private UserFileMapper userFileMapper;

    @Autowired
    private UserSettingMapper userSettingMapper;

    @Autowired
    private UserAuthorizeMapper userAuthorizeMapper;

    @Autowired
    private ZtskUtil ztskUtil;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean register(UserRegisterParam userRegisterParam) throws Exception {
        // 先验证短信验证码是否正确
        if (!commonUtil.checkCode(CommonConstant.SMS_CODE + userRegisterParam.getMobile(),
                userRegisterParam.getSmsCode())) {
            throw new BusinessException(500, "短信验证码错误");
        }

        // 判断当前手机号是否已存在用户
        User user = userMapper.selectOne(Wrappers.<User>lambdaQuery()
                .eq(User::getMobile, userRegisterParam.getMobile())
                .ne(User::getStatus, 0));
        if (ObjectUtil.isNotNull(user)) {
            throw new BusinessException(500, "当前手机号已存在用户，请直接使用手机号登录");
        }

        user = new User();
        BeanUtils.copyProperties(userRegisterParam, user);
        user.setNickname(userRegisterParam.getUsername());
        user.setUserNo(StringUtil.random(32)); // 生成用户ID
        user.setSalt(SHA256Util.getSHA256Str(UUID.randomUUID().toString()));
        // HA256S加密
        user.setPassword(SHA256Util.getSHA256Str(user.getPassword() + user.getSalt()));
        user.setStatus(1); // 状态为正常
        userMapper.insert(user);

        return true;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean updateUser(UserUpdateParam userUpdateParam) throws Exception {
        // 获取当前登录用户信息
        User user = userMapper.selectById(LoginUtil.getUserId());
        if (user == null) {
            throw new BusinessException(500, "用户信息异常");
        }
        BeanUtils.copyProperties(userUpdateParam, user);
        user.setUpdateTime(new Date());
        return super.updateById(user);
    }

    @Override
    public boolean updatePassword(UpdatePasswordParam updatePasswordParam) throws Exception {
        // 先验证短信验证码是否正确
        if (!"666666".equals(updatePasswordParam.getSmsCode())) {
            if (!commonUtil.checkCode(CommonConstant.SMS_CODE + updatePasswordParam.getMobile(),
                    updatePasswordParam.getSmsCode())) {
                throw new BusinessException(500, "短信验证码错误");
            }
        }

        // 获取当前登录用户信息
        User user = userMapper.selectById(LoginUtil.getUserId());
        if (user == null) {
            throw new BusinessException(500, "用户信息异常");
        }
        // 判断手机号是否一致
        if (!user.getMobile().equals(updatePasswordParam.getMobile())) {
            throw new BusinessException(500, "手机号不一致");
        }

        // 重新生成盐
        user.setSalt(SHA256Util.getSHA256Str(UUID.randomUUID().toString()));
        // HA256S加密
        user.setPassword(SHA256Util.getSHA256Str(updatePasswordParam.getPassword() + user.getSalt()));
        user.setUpdateTime(new Date());
        userMapper.updateById(user);

        // 代理商需要退出智通那边的登录
        if (LoginUtil.getUserType() == 3) {
            // 退出智通视控所有登录
            ztskUtil.logout(user.getMobile());
        }

        // 退出所有登录
        LoginUtil.logoutAll(user.getId());

        return true;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean deleteUser(Long id) throws Exception {
        return super.removeById(id);
    }

    @Override
    public Paging<UserVo> getUserPageList(UserPageParam userPageParam) throws Exception {
        Page<User> page = new PageInfo<>(userPageParam);
        IPage<UserVo> iPage = userMapper.getUserList(page, userPageParam);
        return new Paging<>(iPage);
    }

    @Override
    public LoginUserInfoVo login(LoginParam loginParam) {

        // 获取用户真实密码
        String password = commonUtil.getDecryptStr(loginParam.getPassword(), loginParam.getSaltKey(), false);
        String macNo = commonUtil.getDecryptStr(loginParam.getMacNo(), loginParam.getSaltKey(), true);

        // 获取当前登录用户信息
        User user = userMapper.selectOne(Wrappers.<User>lambdaQuery().eq(User::getUsername, loginParam.getUsername()));
        if (ObjectUtil.isNull(user)) {
            throw new BusinessException(500, "用户不存在");
        }

        String dbPassword = SHA256Util.getSHA256Str(password + user.getSalt());
        if (user == null || !user.getPassword().equals(dbPassword)) {
            // 添加逻辑，当天输入密码错误冻结用户
            if (user != null && user.getStatus() == 1) {
                // 用户每天输错密码不得超过最大限制数
                long errorNum = redisUtil.incr(CommonConstant.PASSWORD_ERROR_NUM + user.getId(), 1);
                if (errorNum > PASSWORD_ERROR_NUM) {

                    // 密码多次错误冻结用户账号，保护账号安全，可次日自动解冻也可由管理员手动解冻
                    user.setStatus(3);
                    user.setUpdateTime(new Date());

                    throw new BusinessException(500, "密码输入错误次数过多账号已冻结，次日将自动解除");
                }
                // 设置当前计数器有效期,当前日期到晚上23：59:59
                redisUtil.expire(CommonConstant.PASSWORD_ERROR_NUM + user.getId(), DateUtil.timeToMidnight());
            }
            // 此处写法固定，防止有人用脚本尝试账号
            throw new BusinessException(500, "用户名或密码错误");
        }
        if (user.getStatus() != 1) {
            throw new BusinessException(500, "账号状态异常，请联系管理员");
        }

        // 登录成功保存token信息
        String token = UUID.randomUUID().toString();

        // 获取用户详细信息
        LoginUserInfoVo loginUserVo = UserConvert.INSTANCE.convert(user);
        loginUserVo.setToken(token);

        //用户详情
        Wrapper wrapper = Wrappers.lambdaQuery(UserDetail.class).eq(UserDetail::getUserId, user.getId());
        List<UserDetail> userDetails = userDetailService.list(wrapper);

        //绑定设备信息
        wrapper = Wrappers.lambdaQuery(Machine.class).eq(Machine::getMacNo, macNo);
        Machine machine = machineService.getOne(wrapper);
        if (ObjectUtil.isNull(machine)) {
            throw new BusinessException(MachineCodeEnum.MACHINE_NO_EXSIT);
        }

        //店铺详情
        Set<Long> businessIds = userDetails.stream().map(UserDetail::getBusinessId).collect(Collectors.toSet());
        wrapper = Wrappers.lambdaQuery(Shop.class).in(Shop::getId, businessIds);
        List<Shop> shops = shopService.list(wrapper);

        Map<Long, Shop> shopMap = shops.stream().collect(Collectors.toMap(Shop::getId, s -> s));
        Shop shop = shopMap.get(machine.getShopId());
        if (ObjectUtil.isNull(shop)) {
            throw new BusinessException(MachineCodeEnum.MACHINE_NO_MATCH);
        }

        //店铺信息
        ShopVo shopVo = ShopConvert.INSTANCE.convert(shop);
        loginUserVo.setShop(shopVo);

        // 将信息放入Redis，有效时间2小时
        redisUtil.set(token, loginUserVo, 2 * 60 * 60);

        // 记录用户登录token
        LoginUtil.saveUserLoginToken(user.getId(), token);

        return loginUserVo;
    }

    @Override
    public UserVo info() {
        // 获取登录用户信息
        User user = userMapper.selectById(LoginUtil.getUserId());
        if (user == null) {
            throw new BusinessException(500, "用户信息异常");
        }
        UserVo userVo = new UserVo();
        BeanUtils.copyProperties(user, userVo);
        UserSetting userSetting = userSettingMapper.selectOne(Wrappers.<UserSetting>lambdaQuery()
                .eq(UserSetting::getUserId, user.getId()));
        UserSettingVo userSettingVo = new UserSettingVo();
        if (userSetting != null) {
            BeanUtils.copyProperties(userSetting, userSettingVo);
        }
        userVo.setUserSettingVo(userSettingVo);
        userVo.setNickname(user.getNickname());
        userVo.setHeadImg(user.getHeadImg());

        // 获取用户微信授权信息
        UserAuthorize openIdAuthorize = userAuthorizeMapper.selectOne(Wrappers.lambdaQuery(UserAuthorize.class)
                .eq(UserAuthorize::getSource, LoginUtil.getUserType())
                .eq(UserAuthorize::getUserId, user.getId())
                .eq(UserAuthorize::getType, 2));
        if (openIdAuthorize != null) {
            userVo.setWxName(openIdAuthorize.getNickname());
        }

        return userVo;
        //return UserConvert.INSTANCE.convertUserVo(user);
    }

    @Override
    public List<UserFileVo> getUserHeadImgList() {
        List<UserFileVo> userFileVos = userFileMapper.getUserFileList(0L, 1);
        // 获取当前用户头像信息
        User user = userMapper.selectById(LoginUtil.getUserId());
        for (UserFileVo userFileVo : userFileVos) {
            if (userFileVo.getUrl().equals(user.getHeadImg())) {
                userFileVo.setStatus(1);
            } else {
                userFileVo.setStatus(0);
            }
        }
        return userFileVos;
    }

    @Override
    public boolean appMsgSendSetting(UserSettingParam userSettingParam) throws Exception {
        UserSetting userSetting = userSettingMapper.selectOne(Wrappers.<UserSetting>lambdaQuery()
                .eq(UserSetting::getUserId, LoginUtil.getUserId()));
        if (userSetting == null) {
            userSetting = new UserSetting();
            userSetting.setUserId(LoginUtil.getUserId());
            userSetting.setAppMsgSend(userSettingParam.getAppMsgSend());
            userSettingMapper.insert(userSetting);
        } else {
            userSetting.setAppMsgSend(userSettingParam.getAppMsgSend());
            userSettingMapper.updateById(userSetting);
        }
        return true;
    }

}
